package engine;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;

import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Interact2D;
import com.threed.jpct.Loader;
import com.threed.jpct.Logger;
import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

import font.GLFont;

public class Planet implements IEntity, IEventListener {
	// LOGIC FIELDS
	private int points;
	private Ownership owner;
	private float radius;
	private SimpleVector position;

	private PointIncrementThread pointIncrementThread;

	// RENDER FIELDS
	private Object3D planetObject;
	private Object3D labelHandler;
	private Object3D border;
	private Object3D icosphere;
	// private Object3D border2;
	private boolean visible;

	private static final GLFont font = new GLFont(new Font("Arial", Font.PLAIN, 20));

	private final float LABEL_HEIGHT = 1.0f;

	public Planet() {
	}

	// LOGIC GETTERS AND SETTERS
	public int getPoints() {
		return points;
	}

	public void setPoints(int points) {
		this.points = points;
	}

	public Ownership getOwner() {
		return owner;
	}

	public void setOwner(Ownership owner) {
		this.owner = owner;
	}

	public float getRadius() {
		return radius;
	}

	public void setRadius(float r) {
		radius = r;
	}

	public void setPosition(float x, float y, float z) {
		position = new SimpleVector(x, y, z);
	}

	public void setPosition(SimpleVector v) {
		position = v;
	}

	public SimpleVector getPosition() {
		return position;
	}

	public Object3D getBoundingSphere() {
		return icosphere;
	}

	// RENDER

	public Object3D getPlanetObject() {
		return planetObject;
	}

	@Override
	public void onFocus() {
		// Logger.log("onFocus");
		border.setVisibility(true);
	}

	@Override
	public void onFocusLoss() {
		// Logger.log("onFocusLoss");
		border.setVisibility(false);
	}

	@Override
	public void onSelect() {
		// Logger.log("onSelect");
	}

	@Override
	public void onRelease() {
		// Logger.log("onRelease");
	}

	@Override
	public void onVisible() {
		visible = true;
	}

	@Override
	public void onInvisible() {
		visible = false;
	}

	@Override
	public void onInit(World world, FrameBuffer buffer) {
		planetObject = Loader.loadOBJ("content/planet.obj", null, radius)[0];
		planetObject.translate(position);
		planetObject.compile();
		world.addObject(planetObject);

		icosphere = Loader.loadOBJ("content/icosphere.obj", null, radius * 0.99f)[0];
		icosphere.translate(position);
		world.addObject(icosphere);

		labelHandler = Object3D.createDummyObj();
		labelHandler.translate(0, -LABEL_HEIGHT * radius, 0);
		labelHandler.addParent(planetObject);

		border = Loader.loadOBJ("content/selected.obj", null, radius)[0];
		border.setBillboarding(true);
		border.addParent(planetObject);
		border.setTransparency(50);
		
		border.setTexture("red");
		border.align(planetObject);
		border.setVisibility(false);
		border.compile();
		border.build();
		world.addObject(border);

		pointIncrementThread = new PointIncrementThread(this);
		pointIncrementThread.start();

		visible = true;
	}

	@Override
	public void onUpdate(World world, FrameBuffer buffer) {
		planetObject.setTexture(owner.toString());

		if (visible) {
			SimpleVector labelHandlerProjection = Interact2D.projectCenter3D2D(world.getCamera(), buffer, labelHandler);

			if (labelHandlerProjection != null) {
				String pointString = Integer.toString(points);
				Dimension d = font.getStringBounds(pointString);
				font.blitString(buffer, pointString, (int) labelHandlerProjection.x - d.width / 2, (int) labelHandlerProjection.y, 100, Color.WHITE);
			}
		}
	}

	/**
	 * Increments planet points. Larger radius -> faster incrementation.
	 */
	private class PointIncrementThread extends Thread {
		private Planet planet;
		private static final int START_OFFSET = 10000;
		private boolean running;

		public PointIncrementThread(Planet planet) {
			this.planet = planet;
			running = true;
		}

		public void run() {
			try {
				Thread.sleep(START_OFFSET);
			} catch (InterruptedException e) {
				Logger.log(e.getMessage());
			}

			while (true) {
				if (running) {
					if (planet.getOwner() != Ownership.NEUTRAL) {
						planet.setPoints(planet.getPoints() + 1);
					}
				}
				try {
					Thread.sleep((long) (10 / planet.getRadius() * 1000));
				} catch (InterruptedException e) {
					Logger.log(e.getMessage());
				}
			}
		}

		public void setRunning(boolean state) {
			running = state;
		}
	}

	public void stopPointIncrementation() {
		pointIncrementThread.setRunning(false);
	}

	public void startPointIncrementation() {
		pointIncrementThread.setRunning(true);
	}
}
